package com.lhkj.ct.meta.modules.psychology.model.bo;

import com.lhkj.ct.base.utils.AviatorUtil;
import com.lhkj.ct.base.utils.TemplateUtil;
import com.lhkj.ct.meta.modules.gauge.common.enums.ScoreType;
import com.lhkj.ct.meta.modules.gauge.model.entity.TblScaleDimNorm;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 描述：维度业务类
 * </p>
 */
public class DimensionBo implements Serializable, Cloneable {

    private final Logger logger = LoggerFactory.getLogger(DimensionBo.class);

    @Getter
    @ApiModelProperty(value = "维度id")
    private String id;

    @Getter
    @ApiModelProperty(value = "量表id")
    private String scaleId;

    @Getter
    @ApiModelProperty(value = "维度名称")
    private String dimName;

    @Getter
    @ApiModelProperty(value = "维度类型 1.普通 2.总评")
    private Integer dimType;

    @Getter
    @ApiModelProperty(value = "性别")
    private String suitSex;

    @Getter
    @ApiModelProperty(value = "最小年龄")
    private Integer minAge;

    @Getter
    @ApiModelProperty(value = "最大年龄")
    private Integer maxAge;

    @Getter
    @ApiModelProperty(value = "计分方式")
    private ScoreType way;

    @Getter
    @ApiModelProperty(value = "是否开启预警")
    private Boolean warn;

    @Getter
    @ApiModelProperty(value = "公式")
    private String formula;

    @Getter
    @ApiModelProperty(value = "排序")
    private Integer sort;

    @Getter
    @ApiModelProperty(value = "原始分公式")
    private String originalExp;

    @Getter
    @ApiModelProperty(value = "标准分公式")
    private String standardExp;

    @Getter
    @ApiModelProperty(value = "分组的id")
    private String groupId;

    @Getter
    @ApiModelProperty(value = "原始分")
    private BigDecimal originalScore;

    @Getter
    @ApiModelProperty(value = "标准分")
    private BigDecimal realScore;

    @Getter
    @ApiModelProperty(value = "是否未匹配到对应的维度", notes = "true即为没有匹配到，false即为有匹配到")
    private boolean nonMatch;

    @Getter
    @ApiModelProperty(value = "维度所关联的题目")
    private List<DimQuestionsBo> dimQuestions;

    @Getter
    @ApiModelProperty(value = "维度所包含的常模")
    private List<TblScaleDimNorm> dimNorms;

    @Getter
    private String ageRanger;

    public void setId(String id) {
        this.id = id;
    }

    public void setScaleId(String scaleId) {
        this.scaleId = scaleId;
    }

    public void setDimName(String dimName) {
        this.dimName = dimName;
    }

    public void setDimType(Integer dimType) {
        this.dimType = dimType;
    }

    public void setSuitSex(String suitSex) {
        this.suitSex = suitSex;
    }

    public void setMinAge(Integer minAge) {
        this.minAge = minAge;
    }

    public void setMaxAge(Integer maxAge) {
        this.maxAge = maxAge;
    }

    public void setWay(ScoreType way) {
        this.way = way;
    }

    public void setWarn(Boolean warn) {
        this.warn = warn;
    }

    public void setFormula(String formula) {
        this.formula = formula;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }

    public void setOriginalExp(String originalExp) {
        this.originalExp = originalExp;
    }

    public void setStandardExp(String standardExp) {
        this.standardExp = standardExp;
    }

    public void setGroupId(String groupId) {
        this.groupId = groupId;
    }

    public void setOriginalScore(BigDecimal originalScore) {
        this.originalScore = originalScore;
    }

    public void setRealScore(BigDecimal realScore) {
        this.realScore = realScore;
    }

    public void setNonMatch(boolean nonMatch) {
        this.nonMatch = nonMatch;
    }

    public void setDimQuestions(List<DimQuestionsBo> dimQuestions) {
        this.dimQuestions = dimQuestions;
    }

    public void setDimNorms(List<TblScaleDimNorm> dimNorms) {
        this.dimNorms = dimNorms;
    }

    public void builderFormula() {
        if (getWay() == ScoreType.IGNORE) {
            this.setOriginalExp("nil");
            this.setStandardExp("nil");
            return;
        }
        String originalExp = dimQuestions.stream().map(DimQuestionsBo::getComputeFormula).collect(Collectors.joining("+"));
        this.setOriginalExp(originalExp);
        // 初始化标准分公式
        String formula = getFormula();
        /*
         * tips 如果设置为标准分公式,几种情况
         * 1.含有Score(Score*2+7)
         * 2.nil(不进行计算)
         * 3.有题目的(NO1+NO2/3)
         * 4.含有其他维度的 ({{维度1}} + {{维度2}})
         */
        if (getWay() == ScoreType.STANDARD && StringUtils.isNotBlank(getFormula())) {
            // 处理题目权重
            for (DimQuestionsBo dimQuestion : dimQuestions) {
                // 如果没有设置权重公式则不需要进行替换
                if (StringUtils.isBlank(dimQuestion.getFormula())) {
                    continue;
                }
                // 要替换的变量
                String variableToReplace = dimQuestion.getName();
                // 替换后的表达式
                String replacementExpression = "(" + dimQuestion.getComputeFormula() + ")";
                // 构建正则表达式，匹配指定的变量名，但排除特定情况（在变量名后面紧跟数字或其他字符的情况）
                String regex = "\\b" + variableToReplace + "(?![0-9])\\b";
                // 编译正则表达式
                Pattern pattern = Pattern.compile(regex);
                // 使用Matcher进行匹配和替换
                Matcher matcher = pattern.matcher(formula);
                String result = matcher.replaceAll(replacementExpression);
                setFormula(result);
            }

            // 如果公式中包含Score,Score代表的是将选择的题目全部相加
            if (getFormula().contains("Score") && CollectionUtils.isNotEmpty(dimQuestions)) {
                formula = getFormula().replace("Score", "(" + originalExp + ")");
            }
            formula = TemplateUtil.replaceTemplate(formula, "\\{\\{([^\\}]+)\\}\\}")
                    // 清除变量里面特殊字符串—，因为这个符号在维度名称里面可出现
                    .replaceAll("[—【】]", "");
        }
        this.setStandardExp(formula);
        String ageRanger = StringUtils.EMPTY;
        if (Objects.nonNull(getMinAge()) && Objects.nonNull(getMaxAge())) {
            ageRanger = getMinAge() + "<=age && age<=" + getMaxAge();
        }
        this.ageRanger = ageRanger;
        logger.info("维度【{}】原始分公式：{}", dimName, getOriginalExp());
        logger.info("维度【{}】标准分公式：{}", dimName, getStandardExp());
    }

    /**
     * <p>
     * 根据维度计算原始分和标准分
     * </p>
     *
     * @param env 参数
     */
    public DimensionBo computeDimScore(Map<String, Object> env) {
        if (getWay() == ScoreType.IGNORE || "nil".equals(getStandardExp())) {
            this.setOriginalScore(null);
            this.setRealScore(null);
            return this;
        }
        if (nonMatch) {
            this.setOriginalScore(BigDecimal.ZERO);
            this.setRealScore(BigDecimal.ZERO);
            return this;
        }
        // 如果有选择题目
        if (StringUtils.isNotBlank(getOriginalExp())) {
            // 原始分
            Object compute = AviatorUtil.compute(env, getOriginalExp());
            if (compute != null) {
                this.setOriginalScore(NumberUtils.toScaledBigDecimal(new BigDecimal(String.valueOf(compute))));
            }
        }
        // 如果设置标准分方式
        if (getWay() == ScoreType.STANDARD && StringUtils.isNotBlank(getStandardExp())) {
            Object compute1 = AviatorUtil.compute(env, getStandardExp());
            if (compute1 != null) {
                this.setRealScore(NumberUtils.toScaledBigDecimal(new BigDecimal(String.valueOf(compute1))));
            }
            // 如果设置原始分，则默认标准分等于原始分
        } else {
            this.setRealScore(this.getOriginalScore());
        }
        logger.info("维度【{}】原始分：{}", dimName, getOriginalScore());
        logger.info("维度【{}】标准分：{}", dimName, getRealScore());
        return this;
    }

//    /**
//     * <p>
//     * 计算总评的原始分和标准分
//     * </p>
//     */
//    public DimensionBo computeTotalScore(Map<String, Object> env) {
//        if ("nil".equals(getStandardExp())) {
//            this.setOriginalScore(null);
//            this.setRealScore(null);
//            return this;
//        }
//        return computeDimScore(env);
//    }

    public DimensionBo clone() {
        try {
            return (DimensionBo) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }
}
